package com.to.aboomy.banner;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrHelper;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DependentLayout;
import ohos.agp.components.StackLayout;
import ohos.agp.components.TableLayout;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.Path;
import ohos.agp.utils.Color;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.utils.RectFloat;
import ohos.agp.window.service.Display;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;
import ohos.global.icu.util.ValueIterator;

import static ohos.agp.animation.Animator.CurveType.ACCELERATE_DECELERATE;


/**
 * @since 2021-07-20
 */
public class IndicatorView extends Component implements Indicator, Component.DrawTask, Component.EstimateSizeListener {
    private RectFloat rectF = null;
    private int pagerCount;
    private final Paint indicatorPaint;
    private Context context;
    private int selectedPage;
    private float offset;
    private float offsetPixels;
    private Path path;
    private Color unColor = Color.GRAY;
    private Color selectedColor = Color.WHITE;

    /*--------------- 核心控制点大小距离参数 ---------------*/
    private float indicatorRadius;
    private float indicatorRatio = 1.0f;
    private float indicatorSelectedRadius;
    private float indicatorSelectedRatio = 1.0f;
    private float indicatorSpacing;
    int displayWith = 0;
    /*--------------- 核心控制点大小距离参数end ---------------*/

    public static int INDICATOR_CIRCLE = 0;
    public static int INDICATOR_CIRCLE_RECT = 1;
    public static int INDICATOR_BEZIER = 2;
    public static int INDICATOR_DASH = 3;
    public static int INDICATOR_BIG_CIRCLE = 4;
    /**
     * indicator样式
     */
    private int indicatorStyle;

    private boolean isAutoLoop =false;
    /**
     * 控制在banner中的位置
     */
    private DependentLayout.LayoutConfig params;

    public IndicatorView(Context context) {
        this(context, null);
    }

    public IndicatorView(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
        this.context = context;
    }

    public IndicatorView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        Display display = DisplayManager.getInstance().getDefaultDisplay(context).get();
        displayWith = display.getAttributes().width;
        indicatorRadius = AttrHelper.fp2px(3.5f, context);
        indicatorSelectedRadius = AttrHelper.fp2px(3.5f, context);
        indicatorSpacing = AttrHelper.fp2px(10, context);
        // 设置测量组件的监听器
        rectF = new RectFloat();
        indicatorPaint = new Paint();
        indicatorPaint.setAntiAlias(true);
        indicatorPaint.setStyle(Paint.Style.FILLANDSTROKE_STYLE);
        indicatorPaint.setColor(Color.BLUE);
        this.setClipEnabled(false);
        addDrawTask(this);

    }

    @Override
    public void initIndicatorCount(int pagerCount) {
        this.pagerCount = pagerCount;
        setVisibility(pagerCount > 1 ? VISIBLE : HIDE);
        postLayout();
    }

    @Override
    public Component getView() {
        return this;
    }

    @Override

    public DependentLayout.LayoutConfig getParams() {
        if (params == null) {
            params = new DependentLayout.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_CONTENT, 50);
            params.addRule(DependentLayout.LayoutConfig.ALIGN_PARENT_BOTTOM);
            params.addRule(DependentLayout.LayoutConfig.CENTER_IN_PARENT);
            params.addRule(DependentLayout.LayoutConfig.BELOW);
            params.setMarginBottom(AttrHelper.vp2px(10, context));
        }
        return params;
    }

    @Override
    public void setAutoStau(Boolean isAuto) {
        this.isAutoLoop = isAuto;
    }

    @Override
    public void onPageSliding(int position, float positionOffset, int positionOffsetPixels) {
        System.out.println("selectedPage================" + position + "=======positionOffset=" + positionOffset);
        selectedPage = position;
        offset = positionOffset;
        offsetPixels = positionOffsetPixels;
        postLayout();
        invalidate();
    }

    @Override
    public void onPageSlideStateChanged(int i) {

    }


    @Override
    public void onPageChosen(int i) {

    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        System.out.println("fuck++");
        indicatorPaint.setAntiAlias(true);
        if (pagerCount == 0) {
            return;
        }
        float midY = 30 / 2.0f + 0.5f;
        if (indicatorStyle == INDICATOR_CIRCLE) {
            LogUtils.log(LogUtils.INFO, "test", "drawCircle");
            System.out.println("fuck111++");
            drawCircle(canvas, midY);
        } else if (indicatorStyle == INDICATOR_CIRCLE_RECT) {
            System.out.println("fuck222++");
            LogUtils.log(LogUtils.INFO, "test", "drawCircleRect");
            drawCircleRect(canvas, midY);

        } else if (indicatorStyle == INDICATOR_BEZIER) {
            System.out.println("fuck333++");
            LogUtils.log(LogUtils.INFO, "test", "drawBezier");
            drawBezier(canvas, midY);
        } else if (indicatorStyle == INDICATOR_DASH) {
            drawDash(canvas, midY);
        } else if (indicatorStyle == INDICATOR_BIG_CIRCLE) {
            drawBigCircle(canvas, midY);
        }
    }

    @Override
    public boolean onEstimateSize(int widthEstimateConfig, int heightEstimateConfig) {
        int width = Component.EstimateSpec.getSize(widthEstimateConfig);
        int height = Component.EstimateSpec.getSize(heightEstimateConfig);
        setEstimatedSize(
                Component.EstimateSpec.getChildSizeWithMode(width, width, Component.EstimateSpec.NOT_EXCEED),
                Component.EstimateSpec.getChildSizeWithMode(height, height, Component.EstimateSpec.NOT_EXCEED)

        );
        return true;
    }

    private int measureWidth(int widthMeasureSpec) {
        int width = Component.EstimateSpec.getSize(widthMeasureSpec);
        int mode = Component.EstimateSpec.getMode(widthMeasureSpec);
//        int mode = MeasureSpec.getMode(widthMeasureSpec);
        int result = 0;
        switch (mode) {
            case EstimateSpec.PRECISE: // 父组件已确定子组件的大小。
                result = width;
                break;
            case EstimateSpec.NOT_EXCEED: // 父组件已确定子组件的最大大小

            case EstimateSpec.UNCONSTRAINT: //父组件对子组件没有约束,表示子组件可以任意大小
                float ratioSelectedRadius = getRatioSelectedRadius();
                float ratioRadius = getRatioRadius();
                float diameterDistance = Math.max(ratioSelectedRadius, ratioRadius) * 2 * pagerCount;
                float spacingDistance = (pagerCount - 1) * indicatorSpacing;
                float al = ratioSelectedRadius - ratioRadius;
                result = (int) (diameterDistance + spacingDistance + al + getPaddingLeft() + getPaddingRight());
                break;
            default:
                break;
        }
        return result;
    }

    private int measureHeight(int heightMeasureSpec) {
        int mode = Component.EstimateSpec.getMode(heightMeasureSpec);
        int height = Component.EstimateSpec.getSize(heightMeasureSpec);
        int result = 0;
        switch (mode) {
            case EstimateSpec.PRECISE:
                result = height;
                break;
            case EstimateSpec.NOT_EXCEED:
            case EstimateSpec.UNCONSTRAINT:
                float ratioSelectedRadius = getRatioSelectedRadius();
                float ratioRadius = getRatioRadius();
                float diameterDistance = Math.max(ratioSelectedRadius, ratioRadius) * 2;
                result = (int) (diameterDistance + getPaddingTop() + getPaddingBottom());
                break;
            default:
                break;
        }
        return result;
    }

    /**
     * getRatioSelectedRadius
     *
     * @return float
     */
    private float getRatioSelectedRadius() {
        return indicatorSelectedRadius * indicatorSelectedRatio;
    }

    private float interpolatedOffset() {
        System.out.println("offset==" + Math.abs(offset));
        return Math.abs(offset);
    }

    /**
     * getRatioRadius
     *
     * @return float
     */
    private float getRatioRadius() {
        return indicatorRadius * indicatorRatio;
    }

    private void drawCircle(Canvas canvas, float midY) {
        drawPagerCountCircle(canvas, midY);
        float indicatorStartX = indicatorStartX(selectedPage);
        float nextIndicatorStartX = indicatorStartX(getNextPageIndex());
        System.out.println("hahha " + "selectedPage==" + selectedPage +"，NextPageIndex="+getNextPageIndex()+"    index==" + nextIndicatorStartX + "  nextIndicatorStartX==" + nextIndicatorStartX + "   pagerCount" + pagerCount);
        float ratioRadius = getRatioSelectedRadius();
        float left = indicatorStartX - ratioRadius;
        float right = indicatorStartX + ratioRadius;
        float nextLeft = nextIndicatorStartX - ratioRadius;
        float nextRight = nextIndicatorStartX + ratioRadius;
        float leftX = left + (nextLeft - left) * interpolatedOffset();
        float rightX = right + (nextRight - right) * interpolatedOffset();

        rectF.modify(leftX, midY - indicatorSelectedRadius, rightX, midY + indicatorSelectedRadius);
        indicatorPaint.setColor(selectedColor);
        canvas.drawRoundRect(rectF, indicatorSelectedRadius, indicatorSelectedRadius, indicatorPaint);
    }

    private int getNextPageIndex() {
        int nextPageIndex = 0;
        if (offsetPixels > 0) {
            if (selectedPage + 1 > pagerCount - 1) {
                nextPageIndex = 0;
            } else {
                nextPageIndex = selectedPage + 1;
            }
        } else {
            if(isAutoLoop){
                if (selectedPage == pagerCount - 1) {
                    nextPageIndex = 0;
                }
            }else {
                if (selectedPage - 1 < 0) {
                    nextPageIndex = pagerCount - 1;
                } else {
                    nextPageIndex = selectedPage - 1;
                }
            }
        }
        return nextPageIndex;
    }

    private void drawPagerCountCircle(Canvas canvas, float midY) {
        indicatorPaint.setColor(unColor);
        for (int i = 0; i < pagerCount; i++) {
            float startCx = indicatorStartX(i);
            float ratioIndicatorRadius = getRatioRadius();
            float left = startCx - ratioIndicatorRadius;
            float top = midY - indicatorRadius;
            float right = startCx + ratioIndicatorRadius;
            float bottom = midY + indicatorRadius;
            rectF = new RectFloat(left, top, right, bottom);
            rectF.modify(left, top, right, bottom);
            canvas.drawRoundRect(rectF, indicatorRadius, indicatorRadius, indicatorPaint);
        }
    }

    private float indicatorStartX(int index) {
        float ratioRadius = getRatioRadius();
        float ratioSelectedRadius = getRatioSelectedRadius();
        float ratioIndicatorRadius = Math.max(ratioRadius, ratioSelectedRadius);
        float centerSpacing = ratioIndicatorRadius * 2.0f + indicatorSpacing;
        float ssx = (displayWith - centerSpacing * pagerCount) / 2;
        float centerX = ratioIndicatorRadius + getPaddingLeft() + centerSpacing * index;
        /*
           为了适配INDICATOR_DASH样式， measure 中默认多增加了 ratioIndicatorRadius - ratioRadius 的高度和宽度
           除了INDICATOR_DASH样式下，其他样式需要增加indicatorSelectedRadius一半的距离，让位置居中。
         */
        return centerX + (indicatorStyle == INDICATOR_DASH ? 0 : (ratioIndicatorRadius - ratioRadius) / 2) + ssx;
    }

    private void drawCircleRect(Canvas canvas, float midY) {
        drawPagerCountCircle(canvas, midY);
        float indicatorStartX = indicatorStartX(selectedPage);
        float NextindicatorStartX = indicatorStartX(getNextPageIndex());
        float ratioRadius = getRatioSelectedRadius();
        float left = indicatorStartX - ratioRadius;
        float right = indicatorStartX + ratioRadius;
        float offset = interpolatedOffset();
        System.out.println("shirt==" + offset);
        float distance = indicatorSpacing + Math.max(getRatioRadius(), ratioRadius) * 2;//一个的间隔
        float leftX = 0;
        float rightX = 0;
        float allDistance = NextindicatorStartX + ratioRadius - indicatorStartX;
        if (getNextPageIndex() == 0 && selectedPage == pagerCount) {   //最后一页向后翻
            if (offset <= 0.5F) {        // 一般的时候全部填充
                rightX = indicatorStartX + ratioRadius;
                leftX = rightX + allDistance * offset * 2;
                System.out.println("shirt2  rightX==" + rightX);
                System.out.println("shirt2  leftX==" + leftX);
            } else if (offset > 0.5F) {
                leftX = NextindicatorStartX - ratioRadius;
                rightX = indicatorStartX + allDistance * (offset - 0.5f) * 2;
            }

        } else if (getNextPageIndex() == pagerCount - 1) { //第一页向前翻
            if (offset <= 0.5F) {        // 一般的时候全部填充
                leftX = indicatorStartX - ratioRadius;
                rightX = leftX + allDistance * offset * 2 + ratioRadius * 2;
            } else if (offset > 0.5F) {
                rightX = NextindicatorStartX + ratioRadius;
                allDistance = allDistance - ratioRadius * 2;
                leftX = indicatorStartX + allDistance * (offset - 0.5f) * 2;
            }

        } else {
            if (NextindicatorStartX > indicatorStartX) { //向左滑动，下一页
                if (offset <= 0.5F) {        // 一般的时候全部填充
                    leftX = indicatorStartX - ratioRadius;
                    rightX = leftX + allDistance * offset * 2 + ratioRadius * 2;
                } else if (offset > 0.5F) {
                    rightX = NextindicatorStartX + ratioRadius;
                    allDistance = allDistance - ratioRadius * 2;
                    leftX = indicatorStartX + allDistance * (offset - 0.5f) * 2;
                }

            } else { //向右滑动，上一页
                if (offset <= 0.5F) {
                    rightX = indicatorStartX + ratioRadius;
                    leftX = rightX + allDistance * offset * 2 - ratioRadius * 2;
                } else if (offset > 0.5F) {
                    leftX = NextindicatorStartX - ratioRadius;
                    rightX = indicatorStartX + allDistance * (offset - 0.5f) * 2;
                }
            }
        }

        rectF.modify(leftX, midY - indicatorSelectedRadius, rightX, midY + indicatorSelectedRadius);
        System.out.println("fuck7==  leftX==" + leftX + "  rightX==" + rightX);
        indicatorPaint.setColor(selectedColor);
        System.out.println("fuck666==" + indicatorSelectedRadius);
        canvas.drawRoundRect(rectF, indicatorSelectedRadius, indicatorSelectedRadius, indicatorPaint);
    }

    private void drawBezier(Canvas canvas, float midY) {
        drawPagerCountCircle(canvas, midY);
        if (path == null) path = new Path();
        float indicatorStartX = indicatorStartX(selectedPage);
        float nextIndicatorStartX = indicatorStartX(getNextPageIndex());
        float leftOff = 0;

        if (offset < 0.5) {
            leftOff = (float) (offset * 0.1);
        } else if (offset > 0.3 && offset < 0.8) {
            leftOff = (float) (offset * 0.4);
        } else {
            leftOff = offset;
        }
        float leftX = indicatorStartX + (nextIndicatorStartX - indicatorStartX) * leftOff;
        float rightX = indicatorStartX + (nextIndicatorStartX - indicatorStartX) * offset;
        float ratioSelectedRadius = getRatioSelectedRadius();
        float minRadius = indicatorSelectedRadius * 0.57f;
        float minRatioRadius = minRadius * indicatorSelectedRatio;
        float leftRadius = ratioSelectedRadius + (minRatioRadius - ratioSelectedRadius) * interpolatedOffset();
        float rightRadius = minRatioRadius + (ratioSelectedRadius - minRatioRadius) * offset;
        float leftTopOrBottomOffset = (indicatorSelectedRadius - minRadius) * interpolatedOffset();
        float rightTopOrBottomOffset = (indicatorSelectedRadius - minRadius) * offset;
        indicatorPaint.setColor(selectedColor);
        rectF.modify(leftX - leftRadius, midY - indicatorSelectedRadius + leftTopOrBottomOffset, leftX + leftRadius, midY + indicatorSelectedRadius - leftTopOrBottomOffset);
        canvas.drawRoundRect(rectF, leftRadius, leftRadius, indicatorPaint);
        rectF.modify(rightX - rightRadius, midY - minRadius - rightTopOrBottomOffset, rightX + rightRadius, midY + minRadius + rightTopOrBottomOffset);
        canvas.drawRoundRect(rectF, rightRadius, rightRadius, indicatorPaint);
        path.reset();
        path.moveTo(rightX, midY);
        System.out.println("bezier== rightX==" + rightX + "midY==" + midY);
        path.lineTo(rightX, midY - minRadius - rightTopOrBottomOffset);
        path.quadTo(rightX + (leftX - rightX) / 2.0f, midY, leftX, midY - indicatorSelectedRadius + leftTopOrBottomOffset);
        path.lineTo(leftX, midY + indicatorSelectedRadius - leftTopOrBottomOffset);
        path.quadTo(rightX + (leftX - rightX) / 2.0f, midY, rightX, midY + minRadius + rightTopOrBottomOffset);
        path.close();
        canvas.drawPath(path, indicatorPaint);
    }

    private void drawDash(Canvas canvas, float midY) {
        float offset = interpolatedOffset();
        //默认dash的长度，设置ratio控制长度
        float ratioSelectedRadius = getRatioSelectedRadius();
        float ratioIndicatorRadius = getRatioRadius();
        float distance = ratioSelectedRadius - ratioIndicatorRadius;
        float distanceOffset = distance * offset;
        int nextPage = getNextPageIndex();
        boolean isNextFirst = nextPage == 0;
        indicatorPaint.setColor(unColor);
        for (int i = 0; i < pagerCount; i++) {
            float startCx = indicatorStartX(i);
            if (isNextFirst) startCx += distanceOffset;
            float left = startCx - ratioIndicatorRadius;
            float top = midY - indicatorRadius;
            float right = startCx + ratioIndicatorRadius;
            float bottom = midY + indicatorRadius;
            if (selectedPage + 1 <= i) {
                rectF.modify(left + distance, top, right + distance, bottom);
            } else {
                rectF.modify(left, top, right, bottom);
            }
            canvas.drawRoundRect(rectF, indicatorRadius, indicatorRadius, indicatorPaint);
        }
        indicatorPaint.setColor(selectedColor);

        if (offset < 0.99f) {
            float leftX = indicatorStartX(selectedPage) - ratioSelectedRadius;
            if (isNextFirst) leftX += distanceOffset;
            float rightX = leftX + ratioSelectedRadius * 2 + distance - distanceOffset;
            rectF.modify(leftX, midY - indicatorSelectedRadius, rightX, midY + indicatorSelectedRadius);
            canvas.drawRoundRect(rectF, indicatorSelectedRadius, indicatorSelectedRadius, indicatorPaint);
        }
        if (offset > 0.1f) {
            float nextRightX = indicatorStartX(nextPage) + ratioSelectedRadius + (isNextFirst ? distanceOffset : distance);
            float nextLeftX = nextRightX - ratioSelectedRadius * 2 - distanceOffset;
            rectF.modify(nextLeftX, midY - indicatorSelectedRadius, nextRightX, midY + indicatorSelectedRadius);
            canvas.drawRoundRect(rectF, indicatorSelectedRadius, indicatorSelectedRadius, indicatorPaint);
        }
    }


    private void drawBigCircle(Canvas canvas, float midY) {
        drawPagerCountCircle(canvas, midY);
        float offset = interpolatedOffset();
        float indicatorStartX = indicatorStartX(selectedPage);
        System.out.println("indicatorStartX==" + indicatorStartX);
        float nextIndicatorStartX = indicatorStartX(getNextPageIndex());
        float ratioRadius = getRatioRadius();
        float maxRadius = indicatorSelectedRadius;
        float maxRatioRadius = maxRadius * indicatorSelectedRatio;
        float leftRadius = maxRatioRadius - ((maxRatioRadius - ratioRadius) * offset);
        float rightRadius = ratioRadius + ((maxRatioRadius - ratioRadius) * offset);
        float topOrBottomOffset = (maxRadius - indicatorRadius) * offset;
        indicatorPaint.setColor(selectedColor);
        if (offset < 0.99f) {
            float top = midY - maxRadius + topOrBottomOffset;
            float left = indicatorStartX - leftRadius;
            float right = indicatorStartX + leftRadius;
            float bottom = midY + maxRadius - topOrBottomOffset;
            rectF.modify(left, top, right, bottom);
            canvas.drawRoundRect(rectF, leftRadius, leftRadius, indicatorPaint);
        }
        if (offset > 0.1f) {
            float top = midY - indicatorRadius - topOrBottomOffset;
            float left = nextIndicatorStartX - rightRadius;
            float right = nextIndicatorStartX + rightRadius;
            float bottom = midY + indicatorRadius + topOrBottomOffset;
            rectF.modify(left, top, right, bottom);
            canvas.drawRoundRect(rectF, rightRadius, rightRadius, indicatorPaint);
        }
    }

    /**
     * 设置indicator比例，拉伸圆为矩形，控制该比例，default 1.0
     * {@link IndicatorView#getRatioRadius()}
     *
     * @param indicatorRatio indicatorRadius * indicatorRatio
     */
    public IndicatorView setIndicatorRatio(float indicatorRatio) {
        if (this.indicatorRatio == this.indicatorSelectedRatio) {
            this.indicatorSelectedRatio = indicatorRatio;
        }
        this.indicatorRatio = indicatorRatio;
        return this;
    }

    public IndicatorView setIndicatorStyle(int indicatorStyle) {
        this.indicatorStyle = indicatorStyle;
        return this;
    }

    /**
     * 设置indicator的圆角，同时会改变选中时的圆角，default 3.5dp
     *
     * @param indicatorRadius 单位dp
     */
    public IndicatorView setIndicatorRadius(float indicatorRadius) {
        int indicatorRadiusDp = AttrHelper.vp2px(indicatorRadius, context);
        if (this.indicatorRadius == this.indicatorSelectedRadius) {
            this.indicatorSelectedRadius = indicatorRadiusDp;
        }
        this.indicatorRadius = indicatorRadiusDp;
        return this;
    }

    /**
     * 设置选中圆比例，拉伸圆为矩形，控制该比例，默认比例和indicatorRatio一致
     *
     * @param indicatorSelectedRatio indicatorSelectedRadius * indicatorSelectedRatio
     */
    public IndicatorView setIndicatorSelectedRatio(float indicatorSelectedRatio) {
        this.indicatorSelectedRatio = indicatorSelectedRatio;
        return this;
    }

    /**
     * 设置选中的圆角，没有设置，默认和indicatorRadius值一致
     *
     * @param indicatorSelectedRadius 单位dp
     */
    public IndicatorView setIndicatorSelectedRadius(float indicatorSelectedRadius) {
        this.indicatorSelectedRadius = AttrHelper.vp2px(indicatorSelectedRadius, context);
        return this;
    }

    public IndicatorView setIndicatorColor(Color indicatorColor) {
        this.unColor = indicatorColor;
        return this;
    }

    public IndicatorView setIndicatorSelectorColor(Color indicatorSelectorColor) {
        this.selectedColor = indicatorSelectorColor;
        return this;
    }
}
